package com.yys.excel.yysexcel.utils.easyPoi;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.db.Entity;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.yys.excel.yysexcel.common.constant.ExcelStants;
import com.yys.excel.yysexcel.common.enums.ErrorStatus;
import com.yys.excel.yysexcel.common.exception.ServiceException;
import com.yys.excel.yysexcel.entity.ImportExportTask;
import com.yys.excel.yysexcel.entity.export.MergeVo;
import com.yys.excel.yysexcel.entity.export.StyleVo;
import com.yys.excel.yysexcel.mapper.ImportExportMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

public class ExcelUtils {
    /**
     * 导出excel
     *
     * @param datas    数据
     * @param filePath 文件路径
     */
    public static void exportExcel(List<Entity> datas, String filePath) {
        exportExcel(datas, filePath, null, null);
    }

    /**
     * 导出excel
     *
     * @param datas    数据
     * @param filePath 文件路径
     */
    public static void exportExcel(List<Entity> datas, String filePath, StyleVo styleData) {
        exportExcel(datas, filePath, null, styleData);
    }

    /**
     * 导出excel
     *
     * @param datas    数据
     * @param filePath 文件路径
     */
    public static void exportExcel(String id, List<Entity> datas, String filePath, StyleVo styleData) {
        exportExcel(id, datas, filePath, null, styleData, null);
    }

    /**
     * 导出excel
     *
     * @param datas    数据
     * @param filePath 文件路径
     */
    public static void exportExcel(String id, List<Entity> datas, String filePath, StyleVo styleData, TimeInterval timer) {
        try {
            exportExcel(id, datas, filePath, null, styleData, timer);
        } catch (ServiceException e) {
            throw new ServiceException(e.getCode(), "生成excel出错：" + e.getMessage());
        }
    }

    public static void exportExcelThrow(String id, List<Entity> datas, String filePath, Map<String, String> title, StyleVo styleData, TimeInterval timer) {
        try {
            exportExcel(id, datas, filePath, title, styleData, timer);
        } catch (ServiceException e) {
            throw new ServiceException(e.getCode(), "生成excel出错：" + e.getMessage());
        }
    }

    /**
     * 导出excel
     * 导出excel 标题转换
     *
     * @param datas     数据
     * @param filePath  文件路径
     * @param title     标题
     * @param id        id
     * @param styleData 风格数据
     * @param timer     计时器
     */
    public static void exportExcel(String id, List<Entity> datas, String filePath, Map<String, String> title, StyleVo styleData, TimeInterval timer) {
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getBigWriter(filePath);
        //标题转换
        if (MapUtil.isNotEmpty(title)) {
            title.forEach((k, v) -> {
                writer.addHeaderAlias(k, Convert.toStr(v));
            });
        }

        //一次性写出内容，强制输出标题
        write(id, writer, datas, true, timer);

        //设置列宽 行高样式
        if (styleData != null) {
            Map<Integer, Integer> columnWidth = styleData.getColumnWidth();
            if (MapUtil.isNotEmpty(columnWidth)) {
                for (Integer k : columnWidth.keySet()) {
                    if (k == -1) {
                        //如果为-1，表示所有列都为同样的宽度
                        writer.setColumnWidth(k, columnWidth.get(k));
                        break;
                    } else {
                        writer.setColumnWidth(k, columnWidth.get(k));
                    }
                }
            }
            Map<Integer, Integer> rowHeigh = styleData.getRowHeigh();
            if (MapUtil.isNotEmpty(rowHeigh)) {
                for (Integer k : rowHeigh.keySet()) {
                    if (k == -1) {
                        //如果为-1，表示所有列都为同样的宽度
                        writer.setRowHeight(k, rowHeigh.get(k));
                        break;
                    } else {
                        writer.setRowHeight(k, rowHeigh.get(k));
                    }
                }
            }
            //设置某列自动宽度
            List<Integer> autoSizeColumn = styleData.getAutoSizeColumn();
            if (IterUtil.isNotEmpty(autoSizeColumn)) {
                for (Integer k : autoSizeColumn) {
                    //如果第一个为-1，表示所有列为自动大小，不再设置后面的数据 不考虑合并单元格
                    if (k == -1) {
                        writer.autoSizeColumnAll();
                        break;
                    } else {
                        writer.autoSizeColumn(autoSizeColumn.get(k));
                    }
                }
            }
            //设置合并规则
            List<MergeVo> merges = styleData.getMerges();
            if (IterUtil.isNotEmpty(merges)) {
                for (MergeVo merge : merges) {
                    Integer firstColumn = merge.getFirstColumn();
                    Integer firstRow = merge.getFirstRow();
                    Integer lastColumn = merge.getLastColumn();
                    Integer lastRow = merge.getLastRow();
                    Object content = merge.getContent();
                    if (ObjectUtil.isAllNotEmpty(firstColumn, firstRow, lastColumn, lastRow, content)) {
                        writer.merge(firstRow, lastRow, firstColumn, lastColumn, content, false);
                    }
                }
            }
        }

        //关闭writer，释放内存
        writer.close();
    }

    /**
     * 导出excel 标题转换
     *
     * @param datas    数据
     * @param filePath 文件路径
     * @param title    标题
     */
    public static void exportExcel(List<Entity> datas, String filePath, Map<String, String> title, StyleVo styleData) {
        exportExcel(null, datas, filePath, title, styleData, null);
    }

    /**
     * 写
     *
     * @param id               id
     * @param writer           作家
     * @param datas            数据
     * @param isWriteKeyAsHead 写关键负责人吗
     * @param timer            计时器
     */
    public static void write(String id, ExcelWriter writer, List<Entity> datas, boolean isWriteKeyAsHead, TimeInterval timer) {
        //总数据量
        int size = datas.size();
        //进度
        int rate = -1;
        boolean isFirst = true;
        for (int i = 0; i < datas.size(); i++) {
            //查询任务表
            ImportExportTask task = ImportExportMapper.getImportExportTaskById(id);
            if (null != task) {
                // 查看是否主动停止任务
                if (ErrorStatus.ACTIVEOVER.getCode() == task.getStatus()) {
                    throw new ServiceException(ErrorStatus.ACTIVEOVER.getInfo(), ErrorStatus.ACTIVEOVER.getCode());
                } else if (timer.intervalMinute() >= ExcelStants.ACTIVE_TIMEOUT_STATUS) {
                    //超时
                    throw new ServiceException(ErrorStatus.TIMEOUT.getInfo(), ErrorStatus.TIMEOUT.getCode());
                }
                //计算百分比
                int percent = i * 100 / (size - 1);
                if (percent % 10 == 0 && rate != percent) {
                    rate = percent;
                    //记录进度
                    ImportExportMapper.updateProgress(id, rate, "%", timer.intervalSecond());
                }
            }

            Entity entity = datas.get(i);
            writer.writeRow(entity, isFirst && isWriteKeyAsHead);
            if (isFirst) {
                isFirst = false;
            }
        }
    }

    /**
     * excel 导出
     *
     * @param list           数据
     * @param title          标题
     * @param sheetName      sheet名称
     * @param pojoClass      pojo类型
     * @param fileName       文件名称
     * @param isCreateHeader 是否创建表头
     * @param response
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, boolean isCreateHeader, HttpServletResponse response) throws IOException {
        ExportParams exportParams = new ExportParams(title, sheetName, ExcelType.XSSF);
        exportParams.setCreateHeadRows(isCreateHeader);
        defaultExport(list, pojoClass, fileName, response, exportParams);
    }

    /**
     * excel 导出
     *
     * @param list      数据
     * @param title     标题
     * @param sheetName sheet名称
     * @param pojoClass pojo类型
     * @param fileName  文件名称
     * @param response
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) throws IOException {
        defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName, ExcelType.XSSF));
    }

    /**
     * excel 导出
     *
     * @param list         数据
     * @param pojoClass    pojo类型
     * @param fileName     文件名称
     * @param response
     * @param exportParams 导出参数
     */
    public static void exportExcel(List<?> list, Class<?> pojoClass, String fileName, ExportParams exportParams, HttpServletResponse response) throws IOException {
        defaultExport(list, pojoClass, fileName, response, exportParams);
    }

    /**
     * excel 导出
     *
     * @param list     数据
     * @param fileName 文件名称
     * @param response
     */
    public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {
        defaultExport(list, fileName, response);
    }

    /**
     * 默认的 excel 导出
     *
     * @param list         数据
     * @param pojoClass    pojo类型
     * @param fileName     文件名称
     * @param response
     * @param exportParams 导出参数
     */
    private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) throws IOException {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
        downLoadExcel(fileName, response, workbook);
    }

    /**
     * 默认的 excel 导出
     *
     * @param list     数据
     * @param fileName 文件名称
     * @param response
     */
    private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {
        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
        downLoadExcel(fileName, response, workbook);
    }

    /**
     * 下载
     *
     * @param fileName 文件名称
     * @param response
     * @param workbook excel数据
     */
    private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + "." + ExcelTypeEnum.XLSX.getValue(), "UTF-8"));
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    /**
     * excel 导入
     *
     * @param filePath   excel文件路径
     * @param titleRows  标题行
     * @param headerRows 表头行
     * @param pojoClass  pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
        if (StringUtils.isBlank(filePath)) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        params.setNeedSave(true);
        params.setSaveUrl("/excel/");
        try {
            return ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new IOException("模板不能为空");
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    /**
     * excel 导入
     *
     * @param file      excel文件
     * @param pojoClass pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile file, Class<T> pojoClass) throws IOException {
        return importExcel(file, 1, 1, pojoClass);
    }

    /**
     * excel 导入
     *
     * @param file       excel文件
     * @param titleRows  标题行
     * @param headerRows 表头行
     * @param pojoClass  pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
        return importExcel(file, titleRows, headerRows, false, pojoClass);
    }

    /**
     * excel 导入
     *
     * @param file       上传的文件
     * @param titleRows  标题行
     * @param headerRows 表头行
     * @param needVerfiy 是否检验excel内容
     * @param pojoClass  pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, boolean needVerfiy, Class<T> pojoClass) throws IOException {
        if (file == null) {
            return null;
        }
        try {
            return importExcel(file.getInputStream(), titleRows, headerRows, needVerfiy, pojoClass);
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    /**
     * excel 导入
     *
     * @param inputStream 文件输入流
     * @param titleRows   标题行
     * @param headerRows  表头行
     * @param needVerfiy  是否检验excel内容
     * @param pojoClass   pojo类型
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(InputStream inputStream, Integer titleRows, Integer headerRows, boolean needVerfiy, Class<T> pojoClass) throws IOException {
        if (inputStream == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        params.setSaveUrl("/excel/");
        params.setNeedSave(true);
        params.setNeedVerify(needVerfiy);
        try {
            return ExcelImportUtil.importExcel(inputStream, pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new IOException("excel文件不能为空");
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    /**
     * Excel 类型枚举
     */
    enum ExcelTypeEnum {
        XLS("xls"), XLSX("xlsx");
        private String value;

        ExcelTypeEnum(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}